use std::fmt;

use from_pest::FromPest;
use pest::iterators;
use pest_ast::FromPest;
use tracing::debug;
use tracing::trace;

use crate::ast_define::MetaInfo;
use crate::ast_define::Rule;
use crate::ast_define::algebraic_expr::*;
use crate::ast_define::general::*;
use crate::ast_define::get_meta_info;
use crate::ast_define::keyword::*;
use crate::ast_define::literal::*;
use crate::ast_define::operator::*;

// * 常量表达式
// * 注: 使用的 Ident 必须是常量

// ConstExp = { AddExp }
#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::ConstExp))]
pub struct ConstExp {
    pub add_exp: AddExp,
    #[pest_ast(outer(with(get_meta_info)))]
    pub meta_info: MetaInfo,
}

impl fmt::Display for ConstExp {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.add_exp)
    }
}

// * 常量初值 ConstInitVal -> '{' [ ConstInitVal { ',' ConstInitVal } ] '}' | ConstExp

// ConstInitVals_Braces_Wrapper = { "{" ~ (ConstInitVal ~ ("," ~ ConstInitVal)*)? ~ "}" }
#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::ConstInitVals_Braces_Wrapper))]
pub struct ConstInitVals_Braces_Wrapper {
    pub const_init_vals: Vec<ConstInitVal>,
    #[pest_ast(outer(with(get_meta_info)))]
    pub meta_info: MetaInfo,
}

impl fmt::Display for ConstInitVals_Braces_Wrapper {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{{")?;
        let formatted = self.const_init_vals.iter().map(|this| this.to_string());
        let formatted = formatted.collect::<Vec<String>>().join(", ");
        write!(f, "{formatted}")?;
        write!(f, "}}")
    }
}

// ConstInitVal = {
//     ConstInitVals_Braces_Wrapper
//   | ConstExp
// }

#[derive(Debug, PartialEq)]
pub enum ConstInitVal {
    ConstInitVals_Braces_Wrapper(ConstInitVals_Braces_Wrapper),
    ConstExp(ConstExp),
}

impl fmt::Display for ConstInitVal {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ConstInitVal::ConstInitVals_Braces_Wrapper(this) => write!(f, "{this}"),
            ConstInitVal::ConstExp(this) => write!(f, "{this}"),
        }
    }
}

impl<'pest> FromPest<'pest> for ConstInitVal {
    type Rule = Rule;
    type FatalError = from_pest::Void;
    #[tracing::instrument(skip_all)]
    fn from_pest(
        pest: &mut iterators::Pairs<'pest, Rule>,
    ) -> Result<Self, from_pest::ConversionError<from_pest::Void>> {
        trace!("正在解析 ConstInitVal");
        let pair = pest.next().ok_or(from_pest::ConversionError::NoMatch)?;
        trace!("pair in ConstInitVal:\n{pair:#?}");
        let Rule::ConstInitVal = pair.as_rule() else {
            trace!("\n{:#?} != Rule::ConstInitVal", pair.as_rule());
            return Err(from_pest::ConversionError::NoMatch);
        };

        let mut inner = pair.into_inner();
        trace!("inner:\n{inner:#?}");
        let inner_pair = inner.peek().ok_or(from_pest::ConversionError::NoMatch)?;
        trace!("inner_pair:\n{inner_pair:#?}");
        match inner_pair.as_rule() {
            Rule::ConstInitVals_Braces_Wrapper => Ok(ConstInitVal::ConstInitVals_Braces_Wrapper(
                ConstInitVals_Braces_Wrapper::from_pest(&mut inner)?,
            )),
            Rule::ConstExp => Ok(ConstInitVal::ConstExp(ConstExp::from_pest(&mut inner)?)),
            _ => Err(from_pest::ConversionError::NoMatch),
        }
    }
}

// * 常数定义 ConstDef -> Ident { '[' ConstExp ']' } '=' ConstInitVal

// ConstDef = { Ident ~ ("[" ~ ConstExp ~ "]")* ~ ASSIGN ~ ConstInitVal }
#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::ConstDef))]
pub struct ConstDef {
    pub ident: Ident,
    pub const_exp: ConstExp,
    pub assign: ASSIGN,
    pub const_init_val: ConstInitVal,
    #[pest_ast(outer(with(get_meta_info)))]
    pub meta_info: MetaInfo,
}

impl fmt::Display for ConstDef {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.ident)?;
        write!(f, "[{}]", self.const_exp)?;
        write!(f, " {} {}", self.assign, self.const_init_val)
    }
}

// * 常量声明 ConstDecl -> 'const' BType ConstDef {',' ConstDef } ";"

// ConstDecl = { CONST ~ BType ~ ConstDef ~ ("," ~ ConstDef)* ~ ";" }
#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::ConstDecl))]
pub struct ConstDecl {
    pub const_: CONST,
    pub b_type: BType,
    pub const_def: ConstDef,
    #[pest_ast(outer(with(get_meta_info)))]
    pub meta_info: MetaInfo,
}

impl fmt::Display for ConstDecl {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} {}", self.const_, self.b_type)?;
        write!(f, " ")?;
        let formatted = self.const_def.to_string();
        write!(f, "{formatted}")?;
        // * ConstDecl 不自己换行, 因为函数体内外的Decl换行策略不同
        write!(f, ";")
    }
}

// * 变量初值 InitVal -> '{' [ InitVal { ',' InitVal } ] '}' | Exp

// InitVals_Braces_Wrapper = { "{" ~ (InitVal ~ ("," ~ InitVal)*)? ~ "}" }
#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::InitVals_Braces_Wrapper))]
pub struct InitVals_Braces_Wrapper {
    pub init_vals: Vec<InitVal>,
    #[pest_ast(outer(with(get_meta_info)))]
    pub meta_info: MetaInfo,
}

impl fmt::Display for InitVals_Braces_Wrapper {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{{")?;
        let formatted = self.init_vals.iter().map(|this| this.to_string());
        let formatted = formatted.collect::<Vec<String>>().join(", ");
        write!(f, "{formatted}")?;
        write!(f, "}}")
    }
}

// InitVal = {
//     InitVals_Braces_Wrapper
//   | Exp
// }

#[derive(Debug, PartialEq)]
pub enum InitVal {
    InitVals_Braces_Wrapper(InitVals_Braces_Wrapper),
    Exp(Exp),
}

impl fmt::Display for InitVal {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            InitVal::InitVals_Braces_Wrapper(this) => write!(f, "{this}"),
            InitVal::Exp(this) => write!(f, "{this}"),
        }
    }
}

impl<'pest> FromPest<'pest> for InitVal {
    type Rule = Rule;
    type FatalError = from_pest::Void;
    #[tracing::instrument(skip_all)]
    fn from_pest(
        pest: &mut iterators::Pairs<'pest, Rule>,
    ) -> Result<Self, from_pest::ConversionError<from_pest::Void>> {
        trace!("正在解析 InitVal");
        let pair = pest.next().ok_or(from_pest::ConversionError::NoMatch)?;
        trace!("pair in InitVal:\n{pair:#?}");
        let Rule::InitVal = pair.as_rule() else {
            trace!("\n{:#?} != Rule::InitVal", pair.as_rule());
            return Err(from_pest::ConversionError::NoMatch);
        };

        let mut inner = pair.into_inner();
        trace!("inner:\n{inner:#?}");
        let inner_pair = inner.peek().ok_or(from_pest::ConversionError::NoMatch)?;
        trace!("inner_pair:\n{inner_pair:#?}");
        match inner_pair.as_rule() {
            Rule::InitVals_Braces_Wrapper => Ok(InitVal::InitVals_Braces_Wrapper(
                InitVals_Braces_Wrapper::from_pest(&mut inner)?,
            )),
            Rule::Exp => Ok(InitVal::Exp(Exp::from_pest(&mut inner)?)),
            _ => Err(from_pest::ConversionError::NoMatch),
        }
    }
}

// * 变量定义 VarDef ->
// *   Ident { '[' ConstExp ']' } '=' InitVal
// * | Ident { '[' ConstExp ']' }

// Ident_ConstExp_Brackets_Wrapper_Assign_InitVal = { Ident ~ ("[" ~ ConstExp ~ "]")* ~ ASSIGN ~ InitVal }
#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::Ident_ConstExp_Brackets_Wrapper_Assign_InitVal))]
pub struct Ident_ConstExp_Brackets_Wrapper_Assign_InitVal {
    pub ident: Ident,
    pub const_exp: Vec<ConstExp>,
    pub assign: ASSIGN,
    pub init_val: InitVal,
    #[pest_ast(outer(with(get_meta_info)))]
    pub meta_info: MetaInfo,
}

impl fmt::Display for Ident_ConstExp_Brackets_Wrapper_Assign_InitVal {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.ident)?;
        for const_exp in self.const_exp.iter() {
            write!(f, "[{const_exp}]")?;
        }
        write!(f, " {} {}", self.assign, self.init_val)
    }
}

// Ident_ConstExp_Brackets_Wrapper = { Ident ~ ("[" ~ ConstExp ~ "]")* }
#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::Ident_ConstExp_Brackets_Wrapper))]
pub struct Ident_ConstExp_Brackets_Wrapper {
    pub ident: Ident,
    pub const_exp: Vec<ConstExp>,
    #[pest_ast(outer(with(get_meta_info)))]
    pub meta_info: MetaInfo,
}

impl fmt::Display for Ident_ConstExp_Brackets_Wrapper {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.ident)?;
        for const_exp in self.const_exp.iter() {
            write!(f, "[{const_exp}]")?;
        }
        Ok(())
    }
}

// VarDef = {
//     Ident_ConstExp_Brackets_Wrapper_Assign_InitVal
//   | Ident_ConstExp_Brackets_Wrapper
// }

#[derive(Debug, PartialEq)]
pub enum VarDef {
    Ident_ConstExp_Brackets_Wrapper_Assign_InitVal(Ident_ConstExp_Brackets_Wrapper_Assign_InitVal),
    Ident_ConstExp_Brackets_Wrapper(Ident_ConstExp_Brackets_Wrapper),
}

impl fmt::Display for VarDef {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            VarDef::Ident_ConstExp_Brackets_Wrapper_Assign_InitVal(this) => write!(f, "{this}"),
            VarDef::Ident_ConstExp_Brackets_Wrapper(this) => write!(f, "{this}"),
        }
    }
}

impl<'pest> FromPest<'pest> for VarDef {
    type Rule = Rule;
    type FatalError = from_pest::Void;
    #[tracing::instrument(skip_all)]
    fn from_pest(
        pest: &mut iterators::Pairs<'pest, Rule>,
    ) -> Result<Self, from_pest::ConversionError<from_pest::Void>> {
        trace!("正在解析 VarDef");
        let pair = pest.next().ok_or(from_pest::ConversionError::NoMatch)?;
        trace!("pair in VarDef:\n{pair:#?}");
        let Rule::VarDef = pair.as_rule() else {
            trace!("\n{:#?} != Rule::VarDef", pair.as_rule());
            return Err(from_pest::ConversionError::NoMatch);
        };

        let mut inner = pair.into_inner();
        trace!("inner:\n{inner:#?}");
        let inner_pair = inner.peek().ok_or(from_pest::ConversionError::NoMatch)?;
        trace!("inner_pair:\n{inner_pair:#?}");
        match inner_pair.as_rule() {
            Rule::Ident_ConstExp_Brackets_Wrapper_Assign_InitVal => {
                Ok(VarDef::Ident_ConstExp_Brackets_Wrapper_Assign_InitVal(
                    Ident_ConstExp_Brackets_Wrapper_Assign_InitVal::from_pest(&mut inner)?,
                ))
            }
            Rule::Ident_ConstExp_Brackets_Wrapper => Ok(VarDef::Ident_ConstExp_Brackets_Wrapper(
                Ident_ConstExp_Brackets_Wrapper::from_pest(&mut inner)?,
            )),
            _ => Err(from_pest::ConversionError::NoMatch),
        }
    }
}

// * 变量声明 VarDecl -> BType VarDef { ',' VarDef } ';'

// VarDecl = { BType ~ VarDef ~ ("," ~ VarDef)* ~ ";" }
#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::VarDecl))]
pub struct VarDecl {
    pub b_type: BType,
    pub var_def: Vec<VarDef>,
    #[pest_ast(outer(with(get_meta_info)))]
    pub meta_info: MetaInfo,
}

impl fmt::Display for VarDecl {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.b_type)?;
        write!(f, " ")?;
        let formatted = self.var_def.iter().map(|this| this.to_string());
        let formatted = formatted.collect::<Vec<String>>().join(", ");
        write!(f, "{formatted}")?;
        // * VarDecl 不自己换行, 因为函数体内外的Decl换行策略不同
        write!(f, ";")
    }
}

// * 声明 Decl -> ConstDecl | VarDecl
#[allow(clippy::large_enum_variant)]
#[derive(Debug, PartialEq)]
pub enum Decl {
    ConstDecl(ConstDecl),
    VarDecl(VarDecl),
}

impl fmt::Display for Decl {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Decl::ConstDecl(this) => write!(f, "{this}"),
            Decl::VarDecl(this) => write!(f, "{this}"),
        }
    }
}

impl<'pest> FromPest<'pest> for Decl {
    type Rule = Rule;
    type FatalError = from_pest::Void;
    #[tracing::instrument(skip_all)]
    fn from_pest(
        pest: &mut iterators::Pairs<'pest, Rule>,
    ) -> Result<Self, from_pest::ConversionError<from_pest::Void>> {
        trace!("正在解析 Decl");
        let pair = pest.next().ok_or(from_pest::ConversionError::NoMatch)?;
        trace!("pair in Decl:\n{pair:#?}");
        let Rule::Decl = pair.as_rule() else {
            trace!("\n{:#?} != Rule::Decl", pair.as_rule());
            return Err(from_pest::ConversionError::NoMatch);
        };
        let mut inner = pair.into_inner();
        trace!("inner:\n{inner:#?}");
        let inner_pair = inner.peek().ok_or(from_pest::ConversionError::NoMatch)?;
        trace!("inner_pair:\n{inner_pair:#?}");
        match inner_pair.as_rule() {
            Rule::ConstDecl => Ok(Decl::ConstDecl(ConstDecl::from_pest(&mut inner)?)),
            Rule::VarDecl => Ok(Decl::VarDecl(VarDecl::from_pest(&mut inner)?)),
            _ => Err(from_pest::ConversionError::NoMatch),
        }
    }
}
